/*----------------------------------------------------------------
// Copyright (C) 2017 上海,巨人
//
// 模块名：CMd5
// 创建者：Macro Gu
// 修改者列表：
// 创建日期：2017.2.28
// 模块描述：CMd5计算类
//----------------------------------------------------------------*/

#pragma once

#include <string>
#include <fstream>
#include <stdint.h>
#include <string.h>

/* CMd5 declaration. */
class CMd5 {
	public:

		/* Default construct. */
		CMd5();

		/* Construct a CMd5 object with a input buffer. */
		CMd5(const void* input, size_t length);

		/* Construct a CMd5 object with a string. */
		CMd5(const std::string& str);

		/* Construct a CMd5 object with a file. */
		CMd5(std::ifstream& in);

		/* Updating the context with a input buffer. */
		void update(const void* input, size_t length);

		/* Updating the context with a string. */
		void update(const std::string& str);

		/* Updating the context with a file. */
		void update(std::ifstream& in);

		/* Return the message-digest */
		const uint8_t* digest();

		/* Convert digest to string value */
		std::string toString();

		/* Reset the calculate state */
		void reset();

		char* replace(char *source, char *sub, char *rep);
	private:

		/* 
		   CMd5 block update operation. Continues an CMd5 message-digest

		   operation, processing another message block, and updating the

		   context.
		*/
		void update(const uint8_t* input, size_t length);

		/* 
		 CMd5 finalization. Ends an CMd5 message-_digest operation, writing the
		 the message _digest and zeroizing the context.
		 */
		void final();

		/* CMd5 basic transformation. Transforms _state based on block. */
		void transform(const uint8_t block[64]);

		/* 
		   Encodes input (ulong) into output (uint8_t). Assumes length is
		   a multiple of 4.
		*/
		void encode(const uint32_t* input, uint8_t* output, size_t length);

		/* 
		   Decodes input (uint8_t) into output (ulong). Assumes length is
		   a multiple of 4.
		*/
		void decode(const uint8_t* input, uint32_t* output, size_t length);

		/* Convert uint8_t array to hex string. */
		std::string bytesToHexString(const uint8_t* input, size_t length);

		/* class uncopyable */

		CMd5(const CMd5&);

		CMd5& operator=(const CMd5&);

	private:

		uint32_t _state[4]; /* state (ABCD) */

		uint32_t _count[2]; /* number of bits, modulo 2^64 (low-order word first) */

		uint8_t _buffer[64]; /* input buffer */

		uint8_t _digest[16]; /* message digest */
		bool _finished; /* calculate finished ? */
		static const uint8_t PADDING[64]; /* padding for calculate */
		static const char HEX[16];
		enum { BUFFER_SIZE = 1024 };
};

